<!--
 * @Description: 双向链表的封装
 * @Autor: wangxin
 * @Date: 2020-05-30 06:40:13
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2020-06-12 12:32:15
-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      // 封装双向链表
      function DoublyLinkedList() {
        // 定义内部类用于创建节点
        function Node(data) {
          this.data = data
          this.prev = null // 上一个节点引用
          this.next = null // 下一个节点引用
        }
        // 定义属性
        this.head = null // 头部引用
        this.tail = null // 尾部引用
        this.length = 0

        // 1.append 在尾部追加数据
        DoublyLinkedList.prototype.append = function (element) {
          var newNode = new Node(element)
          // 判断链表是否为空
          if (this.length == 0) {
            this.head = newNode
            this.tail = newNode
          } else {
            this.tail.next = newNode
            newNode.prev = this.tail
            this.tail = newNode
          }
          this.length++
        }
        // 2.正向反向遍历
        // 2.1.forwardString 正向遍历转成字符串的方法
        DoublyLinkedList.prototype.forwardString = function () {
          var current = this.head
          var result = ''
          while (current) {
            result += current.data + ' '
            current = current.next
          }
          return result
        }
        // 2.2.reverseString 反向遍历转成字符串的方法
        DoublyLinkedList.prototype.reverseString = function () {
          var current = this.tail
          var result = ''
          while (current) {
            result += current.data + ' '
            current = current.prev
          }
          return result
        }
        // 2.3.toString 正向遍历转成字符串的方法
        DoublyLinkedList.prototype.toString = function () {
          return this.forwardString()
        }
        // 3.insert 在任意位置插入
        DoublyLinkedList.prototype.insert = function (position, element) {
          // 1.判断越界问题
          if (position < 0 || position > this.length) {
            return false
          }
          // 2.创建新节点
          var newNode = new Node(element)
          // 3.插入元素
          if (this.length === 0) {
            this.head = newNode
            this.tail = newNode
          } else {
            if (position === 0) {
              // 插入位置为0
              this.head.prev = newNode
              newNode.next = this.head
              this.head = newNode
            } else if (position === this.length) {
              // 插入最后的位置
              newNode.prev = this.tail
              this.tail.next = newNode
              this.tail = newNode
            } else {
              // 插入中间的位置
              var current = this.head
              var index = 0
              while (index++ < position) {
                current = current.next
              }
              newNode.next = current
              newNode.prev = current.prev
              current.prev.next = newNode
              current.prev = newNode
            }
          }
          this.length++
          return true
        }
        // 4.get 获取指定位置数据
        DoublyLinkedList.prototype.get = function (position) {
          if (position < 0 || position >= this.length) return null
          if (this.length / 2 > position) {
            // 1.从头部开始查找
            var current = this.head
            var index = 0
            while (index++ < position) {
              current = current.next
            }
            return current.data
          } else if (this.length / 2 <= position) {
            // 2.从末尾开始查找
            var current = this.tail
            var index = this.length - 1
            while (index-- > position) {
              current = current.prev
            }
            return current.data
          }
        }
        // 5.indexOf 返回指定数据的位置
        DoublyLinkedList.prototype.indexOf = function (data) {
          var current = this.head
          var index = 0
          while (current) {
            if (current.data == data) {
              return index
            }
            current = current.next
            index++
          }
          return -1
        }
        // 6.updete 更新指定位置的数据
        DoublyLinkedList.prototype.update = function (position, newData) {
          if (position < 0 || position >= this.length) return false
          if (this.length / 2 > position) {
            // 1.从头开始查找
            var current = this.head
            var index = 0
            while (index++ < position) {
              current = current.next
            }
            current.data = newData
          } else {
            // 2.从尾开始查找
            var current = this.tail
            var index = this.length - 1
            while (index-- > position) {
              current = current.prev
            }
            current.data = newData
          }
          return true
        }
        // 7.removeAt 移除并其返回特定元素
        DoublyLinkedList.prototype.removeAt = function (position) {
          if (position < 0 || position >= this.length) return null

          var current = this.head
          if (this.length === 1) {
            this.head = null
            this.tail = null
          } else {
            if (position === 0) {
              this.head.next.prev = null
              this.head = this.head.next
            } else if (position === this.length - 1) {
              current = this.tail
              this.tail.prev.next = null
              this.tail = this.tail.prev
            } else {
              // var current = this.head
              var index = 0
              while (index++ < position) {
                current = current.next
              }
              current.next.prev = current.prev
              current.prev.next = current.next
            }
          }
          this.length -= 1
          return current.data
        }
        // 8.remove 移除指定的数据
        DoublyLinkedList.prototype.remove = function (data) {
          var index = this.indexOf(data)
          this.removeAt(index)
        }
        // 其他方法
        // 9.isEmpty 是否为空
        DoublyLinkedList.prototype.isEmpty = function () {
          return this.length === 0
        }
        // 10.size 返回链表长度
        DoublyLinkedList.prototype.size = function () {
          return this.length
        }
        // 11.getHead 获取链表第一个元素
        DoublyLinkedList.prototype.getHead = function () {
          return this.head.data
        }
        // 12.getTail 获取链表最后一个元素
        DoublyLinkedList.prototype.getTail = function () {
          return this.tail.data
        }
      }

      // 测试代码
      var list = new DoublyLinkedList()
      list.append(1)
      list.append(2)
      list.append(3)
      list.append(4)
    </script>
  </body>
</html>
